package com.xie.stack;

import java.util.Stack;
import java.util.StringTokenizer;

/**
 * @author xiezhendong
 * @date 2022/10/17
 */
public class Calculator {

    /**
     * 存操作符栈
     */
    private Stack<Character> opStack;
    /**
     * 存操作数栈
     */
    private Stack<Double> numStack;
    /**
     * 存放输入的表达式
     */
    private String expression;
    /**
     * 存放表达式计算的状态，0：未计算，1：
     */
    int state;
    /**
     * 计算正确，-1表达式错
     */
    double resultValue = 0;

    /**
     * 设置要计算的表达式
     *
     * @param exp 计算的表达式
     */
    public void setExpression(String exp) {
        expression = exp;
    }

    /**
     * 获取计算状态
     *
     * @return
     */
    public int getState() {
        return state;
    }

    /**
     * 获取表达式的计算值
     *
     * @return
     */
    public double getExpValue() {
        if (state == 0) {
            //如未计算就计算
            process();
        }
        if (state == 1) {
            //如计算正确就返回计算值
            return resultValue;
        } else {
            return 0;
        }
    }

    public void initCalculator() {
        opStack = new Stack<Character>();
        numStack = new Stack<Double>();
        state = 0;
    }

    private void process() {
        String token;
        StringTokenizer tokenizer = new StringTokenizer(expression.replaceAll(" ", ""), "+-*/()", true);
        try {
            while (tokenizer.hasMoreElements()) {
                token = tokenizer.nextToken();
                if (Operation.isOperator(token)) {
                    if (token.equals(Character.toString(Operation.LP))) {
                        opStack.push(token.toCharArray()[0]);
                    } else if (token.equals(Character.toString(Operation.RP))) {
                        while (!opStack.peek().equals(Operation.LP)) {
                            Character action = opStack.pop();
                            this.simplCal(action);
                        }
                        opStack.pop();
                    } else {
                        while (opStack.size() != 0
                                && Operation.P_NoSmall(opStack.peek(), token.toCharArray()[0])) {
                            Character action = opStack.pop();
                            this.simplCal(action);
                        }
                        opStack.push(token.toCharArray()[0]);
                    }
                } else {
                    numStack.add(Double.valueOf(token));
                }
            }

            while (opStack.size() != 0) {
                Character action = opStack.pop();
                this.simplCal(action);
            }

            state = 1;
            resultValue = numStack.pop();

        } catch (Exception e) {
            // 表达式错
            state = -1;
        }
    }

    private void simplCal(int op) {
        double x2 = numStack.pop();
        double x1 = numStack.pop();
        switch (op) {
            case Operation.Plus:
                numStack.push(x1 + x2);
                break;
            case Operation.Minus:
                numStack.push(x1 - x2);
                break;
            case Operation.Mult:
                numStack.push(x1 * x2);
                break;
            case Operation.Div:
                numStack.push(x1 / x2);
                break;
            default:
                throw new RuntimeException("运算符有误");
        }
    }
}
